/*
 * Copyright 2012-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.spring.start.site;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.util.StringUtils;

import com.fasterxml.jackson.databind.ObjectMapper;

import io.spring.initializr.metadata.InitializrMetadataProvider;
import io.spring.initializr.versionresolver.MavenVersionResolver;
import io.spring.initializr.web.project.DefaultProjectRequestPlatformVersionTransformer;
import io.spring.initializr.web.project.DefaultProjectRequestToDescriptionConverter;
import io.spring.initializr.web.project.ProjectGenerationInvoker;
import io.spring.initializr.web.project.ProjectRequest;
import io.spring.initializr.web.project.ProjectRequestPlatformVersionTransformer;
import io.spring.start.site.config.GitlabConfiguration;
import io.spring.start.site.config.GitlabProperties;
import io.spring.start.site.container.SimpleDockerServiceResolver;
import io.spring.start.site.gitlab.GitlabService;
import io.spring.start.site.project.ProjectDescriptionCustomizerConfiguration;
import io.spring.start.site.support.CacheableMavenVersionResolver;
import io.spring.start.site.support.StartInitializrMetadataUpdateStrategy;
import io.spring.start.site.web.GitllabProjectResource;
import io.spring.start.site.web.HomeController;

/**
 * Initializr website application.
 *
 * @author Stephane Nicoll
 */
@EnableAutoConfiguration
@SpringBootConfiguration
@Import(value = { ProjectDescriptionCustomizerConfiguration.class, GitlabConfiguration.class })
@EnableCaching
@EnableAsync
@EnableConfigurationProperties(value = { StartConfigurationProperties.class, GitlabProperties.class })
public class StartApplication {

	public static void main(String[] args) {
		SpringApplication.run(StartApplication.class, args);
	}

	@Bean
	HomeController homeController() {
		return new HomeController();
	}

	@Bean
	StartInitializrMetadataUpdateStrategy initializrMetadataUpdateStrategy(RestTemplateBuilder restTemplateBuilder,
			ObjectMapper objectMapper) {
		return new StartInitializrMetadataUpdateStrategy(restTemplateBuilder.build(), objectMapper);
	}

	@Bean
	CacheableMavenVersionResolver mavenVersionResolver(StartConfigurationProperties properties) throws IOException {
		Path location;
		if (StringUtils.hasText(properties.getMavenVersionResolver().getCacheDirectory())) {
			location = Path.of(properties.getMavenVersionResolver().getCacheDirectory());
		}
		else {
			location = Files.createTempDirectory("version-resolver-cache-");
		}
		return new CacheableMavenVersionResolver(MavenVersionResolver.withCacheLocation(location));
	}

	@Bean
	SimpleDockerServiceResolver dockerServiceResolver() {
		return new SimpleDockerServiceResolver();
	}

	@Bean
	GitllabProjectResource<ProjectRequest> gitllabProjectResource(InitializrMetadataProvider metadataProvider,
			ObjectProvider<ProjectRequestPlatformVersionTransformer> platformVersionTransformer,
			ApplicationContext applicationContext, GitlabService gitlabService, GitlabProperties gitlabProperties) {
		ProjectGenerationInvoker<ProjectRequest> projectGenerationInvoker = new ProjectGenerationInvoker<>(
				applicationContext, new DefaultProjectRequestToDescriptionConverter(platformVersionTransformer
					.getIfAvailable(DefaultProjectRequestPlatformVersionTransformer::new)));
		return new GitllabProjectResource<ProjectRequest>(metadataProvider, projectGenerationInvoker, gitlabService,
				gitlabProperties);
	}

}
